package com.qf.leadnewsarticle.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qf.leadnewsarticle.feign.WeMediaFeignApi;
import com.qf.leadnewsarticle.mapper.ApArticleConfigMapper;
import com.qf.leadnewsarticle.mapper.ApArticleContentMapper;
import com.qf.leadnewsarticle.mapper.ApArticleMapper;
import com.qf.leadnewsarticle.model.dtos.HomePageDto;
import com.qf.leadnewsmodel.pojos.article.ApArticle;
import com.qf.leadnewsarticle.model.pojos.ApArticleConfig;
import com.qf.leadnewsarticle.model.pojos.ApArticleContent;
import com.qf.leadnewsarticle.service.ApArticleService;
import com.qf.leadnewscommon.minio.MinioOperator;
import com.qf.leadnewsmodel.dtos.ResponseResult;
import com.qf.leadnewsmodel.pojos.wemedia.WmNews;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ApAriticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {

    @Autowired
    private ApArticleConfigMapper apArticleConfigMapper;

    @Autowired
    private ApArticleContentMapper apArticleContentMapper;

    @Autowired
    private WeMediaFeignApi weMediaFeignApi;

    @Autowired
    private MinioOperator minioOperator;

    @Autowired
    private Configuration configuration;
    @Autowired
    private ApArticleMapper apArticleMapper;

    @Override
    public ResponseResult load(HomePageDto homePageDto) {
        homePageDto.checkSize();

        List<ApArticle> apArticles = getBaseMapper().loadArticles(homePageDto);
        return ResponseResult.okResult(apArticles);
    }

    @Override
    public ResponseResult loadnew(HomePageDto homePageDto) {
        homePageDto.checkSize();

        List<ApArticle> apArticles = getBaseMapper().loadArticles(homePageDto);
        return ResponseResult.okResult(apArticles);
    }

    @Override
    public ResponseResult loadmore(HomePageDto homePageDto) {
        homePageDto.checkSize();

        List<ApArticle> apArticles = getBaseMapper().loadArticles(homePageDto);
        return ResponseResult.okResult(apArticles);
    }

    @Override
    @Transactional
    public void saveArticle(WmNews wmNews) throws Exception {
        //插入article信息
        ApArticle apArticle = new ApArticle();
        BeanUtils.copyProperties(wmNews,apArticle);

        //补充或者删除一些信息
        apArticle.setId(null);
        apArticle.setAuthorId(Long.parseLong(wmNews.getUserId()+""));
        //todo：根据作者id，查询作者名称（访问wmmedia服务的wmuser表） done
        String authorName = weMediaFeignApi.findUserNameById(wmNews.getUserId());
        apArticle.setAuthorName(authorName);
        //todo: 根据channelid，查询channel名称（访问wmmedia服务的wmchannel表） done
        String channelName = weMediaFeignApi.findChannelNameById(wmNews.getChannelId());
        apArticle.setChannelName(channelName);

        apArticle.setLayout(wmNews.getType());
        apArticle.setFlag((byte) 0);

        save(apArticle);

        //插入config信息
        ApArticleConfig apArticleConfig = new ApArticleConfig(apArticle.getId());
        apArticleConfigMapper.insert(apArticleConfig);

        //插入content信息
        ApArticleContent apArticleContent = new ApArticleContent();
        apArticleContent.setArticleId(apArticle.getId());
        apArticleContent.setContent(wmNews.getContent());
        apArticleContentMapper.insert(apArticleContent);

        //远程修改wmnews的状态为9
        wmNews.setArticleId(apArticle.getId());
        wmNews.setStatus((short) 9);
        weMediaFeignApi.updateNewsById(wmNews);

        //生成静态html页面
        processStaticHtml(apArticle.getId());
    }

    private void processStaticHtml(Long articleId) throws Exception {
        //根据文章id 查询文章内容对象
        LambdaQueryWrapper<ApArticleContent> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(ApArticleContent::getArticleId,articleId);
        ApArticleContent apArticleContent = apArticleContentMapper.selectOne(queryWrapper);

        String content = apArticleContent.getContent();
        //将字符串转换成一个数组对象
        JSONArray array = JSON.parseArray(content);
        Map map = new HashMap();
        map.put("content",array);

        //获取模板
        Template template = configuration.getTemplate("article.ftl");
        //将模板和数据整合
        /*
            todo: 我们数据是内存中保存的，如果自媒体端发布文章的人非常多，此时这个业务就会被大量执行
                就会有大量数据直接进入服务器的内存，最终会有内存溢出的风险

                解决方案：
                    不要将数据直接存入内存，可以将数据先写入到一个临时文件中。 easyexcel中就是使用这种方式解决内存溢出风险的。
        */
        //内存中的流对象
        StringWriter writer = new StringWriter();
        template.process(map, writer);

        String htmlStr = writer.toString();

        //创建一个内存中的字节输入流
        ByteArrayInputStream is = new ByteArrayInputStream(htmlStr.getBytes(StandardCharsets.UTF_8));

        //上传到minio服务器
        String url = minioOperator.uploadHtml(is, articleId + ".html");

        //将ur回写到文章表中
        ApArticle apArticle = apArticleMapper.selectById(articleId);
        apArticle.setStaticUrl(url);
        apArticleMapper.updateById(apArticle);
    }
}
